#include <iterator>
#include "MarkupSTL.h"
#include "global.h"
#include "cmd.h"
#include "Game.h"
#include "RedisClient.h"
#include "Logic.h"
#include "json.h"
#include "Host.h"
#include <limits>
#include "NodeServer.h"
#include "util.h"
// protobuf
#include "1650_agentbackend.pb.h"
#include "5000_record_backend.pb.h"

// http server
#include "handler.h"
#include "http.h"
#include "buffer.h"
#include "listener.h"
#include "mainworker.h"
#include <sys/stat.h>

static CGameServer* g_pGame = NULL;

#define TIMER_CALL_ROCKSDB 10000 //测试socksdb用

#define TIMER_TABLE_REMOVE 1001


MainHandler::MainHandler() : HiveNS::Handler() {

}
MainHandler::~MainHandler(){

}

// from Handler
void MainHandler::onReceiveHttp(HiveNS::Http* pHttp){
    HttpData data;
    data.request_id = pHttp->getHandle();
    data.method = std::string(http_method_str((http_method)pHttp->getParser()->method));
    data.target = std::string(pHttp->getUrl(), pHttp->getUrlLength());
    data.body = std::string(pHttp->getBody(), pHttp->getBodyLength());
    g_pGame->ReceiveHttpData(data);
}
void MainHandler::onCurlResponse(HiveNS::Buffer* pBuffer, uint32 nodeID, uint32 callbackID, bool isRequestOK){
    CurlData data;
    data.callback_id = callbackID;
    data.body = std::string(pBuffer->data(), pBuffer->size());
    data.isOK = isRequestOK;
    g_pGame->ReceiveCurlData(data);
}
void MainHandler::onCloseHttp(HiveNS::Http* pHttp){

}
void MainHandler::onCloseListener(HiveNS::Listener* pListener){

}

CGameServer::CGameServer()
{
    m_pActiveEvent = NULL;
    m_httpListenPort = 18000;
}

CGameServer::~CGameServer()
{
    /*删除rocksdb指针*/
    if (this->m_rocksdbHandler != NULL)
    {
        delete this->m_rocksdbHandler;
        this->m_rocksdbHandler = NULL;
    }
}


bool CGameServer::InitGame()
{

    //StartTimer(TIMER_CALL_ROCKSDB, 40, false);
    StartTimer(TIMER_TABLE_REMOVE, 12*60*60, true);
//    StartTimer(TIMER_TABLE_REMOVE, 60*60, true);

	char szconfig[] = "./config.xml";
	ReadCommonConf(szconfig);

    // 使用全局指针处理业务
    g_pGame = this;
    // 创建httpserver线程
    m_pReceiveLock = new HiveNS::Sync();
    MainHandler* pMainHandler = new MainHandler();
    pMainHandler->retain();
    log_debug("InitGame MainHandler create");
    HiveNS::MainWorker::createInstance();
    HiveNS::MainWorker::getInstance()->setHandler(pMainHandler);
    HiveNS::MainWorker::getInstance()->setListenerAddress("0.0.0.0", m_httpListenPort);
    log_debug("InitGame MainWorker startThread create");
    HiveNS::MainWorker::getInstance()->startThread();

    CreateActiveEvent();

	//创建db
    //CreateRocksdb();
    /*创建rocksdb指针*/
    this->m_rocksdbHandler = new CRocksdb();
    /*打开全局表*/
    std::vector<std::string> CumnFamilyNames;
    CumnFamilyNames.push_back(GAME_EVENT_GLOBAL_TABLE);

    //测试用
    /*CumnFamilyNames.push_back("game_event_global");
    CumnFamilyNames.push_back("game_event");
    CumnFamilyNames.push_back("game_round_settle");
    CumnFamilyNames.push_back("game_round_detail");*/
    //测试用

    /*存储路径和数据库表名*/
    m_rocksdbHandler->OpenRocksDB(m_strPath, CumnFamilyNames);

    //测试用
    /*std::string tablename = "game_event_global";
    std::string strKey = "game_event_101_20240730_id";
    std::string strValue = "1";

    m_rocksdbHandler->WriteValueToDB(tablename, strKey, strValue);
    tablename = "game_event_101_20240730";
    strKey = "1";
    strValue = "123456";
    m_rocksdbHandler->WriteValueToDB(tablename, strKey, strValue);*/
    //测试用

	return true;
}

int CGameServer::OnBYTimeOut(int Timerid)
{
    switch (Timerid)
    {
        case TIMER_TABLE_REMOVE:{
            UpdateCheckRemoveTable();
            break;
        }
        case TIMER_CALL_ROCKSDB:
        {
            test();
            break;
        }
        default:
            break;
    }
	return 0;
}

//测试用
void CGameServer::test()
{
   /* std::vector<std::string> column_family_names;
    column_family_names.push_back("qwe");
    column_family_names.push_back("asd");
    column_family_names.push_back("zxc");
    std::string str("./testdb/20240730");
    CRocksdb rocksdb;
    rocksdb.OpenRocksDB(str, column_family_names);*/

    /*uint32 request_id = 0;
    std::string method = "";
    std::string target = "/data";
    std::string body = "{\"start_id\": 0,\"number\" : 100,\"ccgame_id\" : 101,\"table_name\" : \"game_event\",\"date\" : \"20240730\"}";
    m_gameToDstIdMap[request_id] = 1;
    OnGetMessage(request_id, method, target, body);*/
}

void CGameServer::ReceiveHttpData(HttpData& data){
    m_pReceiveLock->lock();
    m_receiveQueue.push_back(data);
    m_pReceiveLock->unlock();
    SignalActiveEvent();
}
void CGameServer::ReceiveCurlData(CurlData& data){
    m_pReceiveLock->lock();
    m_curlQueue.push_back(data);
    m_pReceiveLock->unlock();
    SignalActiveEvent();
}
void CGameServer::UpdateHttpServer(){
    std::vector<HttpData> httpQueue;
    std::vector<CurlData> curlQueue;
    m_pReceiveLock->lock();
    m_receiveQueue.swap(httpQueue);
    m_curlQueue.swap(curlQueue);
    m_pReceiveLock->unlock();
    for(int i=0; i<(int)httpQueue.size(); ++i){
        HttpData& data = httpQueue[i];
        OnGetMessage(data.request_id, data.method, data.target, data.body);
    }
    for(int i=0; i<(int)curlQueue.size(); ++i){
        CurlData& data = curlQueue[i];
        OnCurlResponse(data.callback_id, data.body, data.isOK);
    }
//    StartTimerMillisecond(HTTP_SERVER_ACTIVE_TIMER, 10, false);
}
void CGameServer::OnGetMessage(uint32 request_id, const std::string& method, const std::string& target, const std::string& body){
    log_debug("OnGetMessage request_id=%d method=%s target=%s body_length=%zu", request_id, method.c_str(), target.c_str(), body.length());
    Json::Reader reader;
    Json::Value root;
    log_debug("OnGetMessage parse json=%s", body.c_str());
    if (!reader.parse(body, root))
    {
        log_error("OnGetMessage parse json failed json=%s", body.c_str());
        ResponseError(request_id, 101);
        return;
    }
    if(target == "/data" || target == "/data/"){
        // TODO 处理PHP的请求
        int result = 0;// 0为成功 >0 为错误码
        int number = 0;// 数量
        int start_id = 0;// 上一个开始的ID，start_id=-1时，获取最新的number条数据
        int ccgame_id = 0;// 子游戏ID
        std::string table_name = "";// 表名
        std::string date = "";// 日期字符串

        // 校验PHP发送过来的参数
        if( !root["ccgame_id"].isInt() || !root["start_id"].isInt() || !root["number"].isInt()
            || !root["table_name"].isString() || !root["date"].isString() ){
            log_error("OnGetMessage json data type error json=%s", body.c_str());
            ResponseError(request_id, 101);
            return;
        }

        ccgame_id = root["ccgame_id"].asInt();
        start_id = root["start_id"].asInt();
        number = root["number"].asInt();
        table_name = root["table_name"].asString();
        date = root["date"].asString();

//        map<int, int>::iterator itCur = m_gameToDstIdMap.find(ccgame_id);
//        if(itCur == m_gameToDstIdMap.end()){
//            log_error("ccgame_id=%d to dstid not found", ccgame_id);
//            ResponseError(request_id, 102);
//            return;
//        }
//        int dstid = itCur->second;
//        // TODO 组合PB消息，发送给GameRecord服务
        int64 id = 0;
        std::vector<std::string> vecValue;
        std::string msg;

        //查找表的最大id，只有获取最新数据时才会去获取
        if(start_id < 0){
            std::string key;
            std::string value;
            key = table_name + "_" + std::to_string(ccgame_id) + "_" + date + "_id";
            std::string table = GAME_EVENT_GLOBAL_TABLE;

            //从数据库中查找
            bool bExist = true;
            if (m_rocksdbHandler->ReadValueFromDB(table, key, value, bExist))
            {
                if (value.empty())
                {
                    result = 102;
                    log_error("OnGetMessage result=%d table_name=%s value.empty", result, table_name.c_str());
                }
                else
                {
                    id = atoll(value.c_str());
                }
            }
            else
            {
                result = 104;
                log_error("OnGetMessage result=%d table_name=%s", result, table_name.c_str());
            }
        }else{
            id = start_id + number;
        }

        //获得数据
        if(result == 0)
        {
            std::string table_name_temp;
            table_name_temp = table_name + "_" + std::to_string(ccgame_id) + "_" + date;
            result = GetPHPTableData(table_name_temp, start_id, id, number, vecValue);
        }

        //编json
        Json::FastWriter writer;
        Json::Value root;
        {
            if (result != 0)
            {
//                Json::Value array(Json::ValueType::objectValue);
                root["result"] = result;
                root["start_id"] = start_id;
                root["number"] = number;
                root["ccgame_id"] = ccgame_id;
                root["table_name"] = table_name;
                root["date"] = date;
//                root["data_array"] = array;   // 如果没有数据，这个字段就不填写
                msg = writer.write(root);
            }
            else
            {
                root["result"] = result;
                root["start_id"] = start_id;
                root["number"] = number;
                root["ccgame_id"] = ccgame_id;
                root["table_name"] = table_name;
                root["date"] = date;
                for (size_t i = 0; i < vecValue.size(); i++)
                {
                    root["data_array"].append(vecValue[i]);
                }
                msg = writer.write(root);
            }
        }

        int status_code = 200;
        std::map<std::string, std::string> headers;
        headers["Content-Type"] = "application/json";
        HiveNS::MainWorker::getInstance()->sendBackToRequest(request_id, status_code, msg, headers);
        //m_pHost->SendtoOneSrv(cmd, pb, dsttype, dstid);
    }
    /*
    else if(target == "/cycle" || target == "/cycle/"){
        int result = 0;
        int ccgame_id = root["ccgame_id"].asInt();
        std::string cycle = root["cycle"].asString();
        std::string date = root["date"].asString();

        // 校验PHP发送过来的参数
        if( !root["ccgame_id"].isInt() || !root["cycle"].isString() || !root["date"].isString() ){
            log_error("OnGetMessage json data type error json=%s", body.c_str());
            ResponseError(request_id, 101);
            return;
        }

        std::string GameBetEventTable = ConcatTableNameByDate(GAME_EVENT_TABLE, ccgame_id, date);
        std::string GameRoundDetailTable = ConcatTableNameByDate(GAME_ROUND_DETAIL_TABLE, ccgame_id, date);
        std::string GameRoundSettleTable = ConcatTableNameByDate(GAME_ROUND_SETTLE_TABLE, ccgame_id, date);
        std::string betKey = "bet_" + cycle;
        std::string detailKey = "detail_" + cycle;

        Json::FastWriter writer;
        Json::Value respRoot;

        // 先获取 bet、detail数据
        std::map<std::string, std::string> valueMap;
        std::vector<std::string> vecTable;
        vecTable.push_back(GameBetEventTable);
        vecTable.push_back(GameRoundDetailTable);
        std::vector<std::string> vecKey;
        vecKey.push_back(betKey);
        vecKey.push_back(detailKey);
        std::string round_no;
        if (m_rocksdbHandler->MultiGet(vecTable, vecKey, valueMap)){
            vecTable.clear();
            vecKey.clear();
            std::string betIDStr;
            std::string detailIDStr;
            std::map<std::string, std::string>::iterator itCur = valueMap.find(betKey);
            if(itCur != valueMap.end()){
                vecTable.push_back(GameBetEventTable);
                vecKey.push_back(itCur->second);
                betIDStr = itCur->second;
            }
            itCur = valueMap.find(detailKey);
            if(itCur != valueMap.end()){
                vecTable.push_back(GameRoundDetailTable);
                vecKey.push_back(itCur->second);
                detailIDStr = itCur->second;
            }
            if(vecTable.size() > 0){
                valueMap.clear();
                if(m_rocksdbHandler->MultiGet(vecTable, vecKey, valueMap)){
                    itCur = valueMap.find(betIDStr);
                    if(itCur != valueMap.end()){
                        respRoot["bet"] = itCur->second;
                        Json::Value data;
                        if (reader.parse(itCur->second, data)){
                            round_no = data["round_no"].asString();
                        }
                    }
                    itCur = valueMap.find(detailIDStr);
                    if(itCur != valueMap.end()){
                        respRoot["detail"] = itCur->second;
                        if(round_no.empty()){
                            Json::Value data;
                            if (reader.parse(itCur->second, data)){
                                round_no = data["round_no"].asString();
                            }
                        }
                    }
                }
            }
        }
        // 解析bet JSON，获取settle_(round_no) 对应的数据
        if(!round_no.empty()){
            bool bExist = false;
            std::string settleKey = "settle_" + round_no;
            std::string idValue;
            m_rocksdbHandler->ReadValueFromDB(GameRoundSettleTable, settleKey, idValue, bExist);
            if(bExist){
                std::string jsonValue;
                m_rocksdbHandler->ReadValueFromDB(GameRoundSettleTable, idValue, jsonValue, bExist);
                if(bExist){
                    respRoot["settle"] = jsonValue;
                }
            }
        }
        respRoot["ccgame_id"] = ccgame_id;
        respRoot["cycle"] = cycle;
        respRoot["date"] = date;
        respRoot["result"] = result;

        std::string msg = writer.write(respRoot);
        int status_code = 200;
        std::map<std::string, std::string> headers;
        headers["Content-Type"] = "application/json";
        HiveNS::MainWorker::getInstance()->sendBackToRequest(request_id, status_code, msg, headers);
    }
    */
    /*
    else if(target == "/settle" || target == "/settle/"){
        int result = 0;
        int ccgame_id = root["ccgame_id"].asInt();
        std::string round_no = root["round_no"].asString();
        std::string date = root["date"].asString();

        // 校验PHP发送过来的参数
        if( !root["ccgame_id"].isInt() || !root["round_no"].isString() || !root["date"].isString() ){
            log_error("OnGetMessage json data type error json=%s", body.c_str());
            ResponseError(request_id, 101);
            return;
        }

        std::string GameRoundSettleTable = ConcatTableNameByDate(GAME_ROUND_SETTLE_TABLE, ccgame_id, date);

        Json::FastWriter writer;
        Json::Value respRoot;

        bool bExist = false;
        std::string settleKey = "settle_" + round_no;
        std::string idValue;
        m_rocksdbHandler->ReadValueFromDB(GameRoundSettleTable, settleKey, idValue, bExist);
        if(bExist){
            std::string jsonValue;
            m_rocksdbHandler->ReadValueFromDB(GameRoundSettleTable, idValue, jsonValue, bExist);
            if(bExist){
                respRoot["settle"] = jsonValue;
            }
        }
        respRoot["ccgame_id"] = ccgame_id;
        respRoot["round_no"] = round_no;
        respRoot["date"] = date;
        respRoot["result"] = result;

        std::string msg = writer.write(respRoot);
        int status_code = 200;
        std::map<std::string, std::string> headers;
        headers["Content-Type"] = "application/json";
        HiveNS::MainWorker::getInstance()->sendBackToRequest(request_id, status_code, msg, headers);
    }
    */
    else{
        log_error("target not handle = %s", target.c_str());
        ResponseError(request_id, 103);
    }


//    Json::FastWriter writer;
//    Json::Value respRoot;
//    respRoot["receive"] = true;
//    respRoot["timestamp"] = (uint32)time(NULL);
//
//    int status_code = 200;
//    std::string respBody = writer.write(respRoot);
//    std::map<std::string, std::string> headers;
//    headers["Content-Type"] = "text/plain";
//    HiveNS::MainWorker::getInstance()->sendBackToRequest(request_id, status_code, respBody, headers);
}
// curl接收到返回结果
void CGameServer::OnCurlResponse(uint32 callback_id, const std::string& body, bool isOK){
    log_debug("OnCurlResponse callback_id=%u isOK=%d body=%s", callback_id, isOK, body.c_str());

}

void CGameServer::ResponseError(uint32 request_id, int result){
    Json::FastWriter writer;
    Json::Value respRoot;
    respRoot["result"] = result;

    int status_code = 200;
    std::string respBody = writer.write(respRoot);
    std::map<std::string, std::string> headers;
    headers["Content-Type"] = "application/json";
    HiveNS::MainWorker::getInstance()->sendBackToRequest(request_id, status_code, respBody, headers);
}

int CGameServer::CreateActiveEvent(){
    if(m_pActiveEvent != NULL){
        return 0;
    }
	m_pActiveEvent = new CActiveEvent();

	int ret = m_pActiveEvent->create();
	if (0 != ret)
	{
		log_error("create CActiveEvent fail");
		return -1;
	}
	m_pActiveEvent->m_pServer = this;
	if (CCReactor::Instance()->AttachPoller(m_pActiveEvent) < 0)
	{
		log_error("attach poller fail");
		return -1;
	}
	return 0;
}
void CGameServer::OnActiveEvent(){
    log_debug("OnActiveEvent called");
    UpdateHttpServer();
}
int CGameServer::SignalActiveEvent(){
    return m_pActiveEvent->signal();
}

void CGameServer::UpdateCheckRemoveTable(void){
    // 检查多天前的数据并删除
    int timeCount = 62*24*60*60;
//    int timeCount = 24*60*60;
    time_t currentTime = time(NULL);
    char temp[32] = {0};
	time_t t = currentTime - timeCount;
	struct tm* ptm = localtime(&t);
	snprintf(temp, 32, "%4d%02d%02d", ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday);
	std::string date(temp);
	std::vector<std::string> vecNames;
	m_rocksdbHandler->LoopFindMatchDateKey(date, vecNames);
	if(vecNames.size() > 0){
        for(int i=0; i<(int)vecNames.size(); ++i){
            m_rocksdbHandler->DropColumnFamily(vecNames[i]);
        }
	}
}

int CGameServer::ProcessPacket(SocketHandler* pHandler, NETInputPacket* inputPkg)
{
    unsigned int cmd = inputPkg->GetCmdType();
    log_debug("ProcessPacket cmd=%u", cmd);
    switch(cmd){
        case record::RECORD_BACKEND_GAME_EVENT_REQ:{
            /*玩家进入房间事件上报*/
            HandleGameEnterRoomeprot(pHandler, inputPkg);
            break;
        }
        case record::RECORD_BACKEND_GAME_BET:{
            /*玩家下注事件*/
            HandleGameBetReprot(pHandler, inputPkg);
            break;
        }
        case record::RECORD_BACKEND_GAME_SETTLE:{
            /*玩家结算事件*/
            HandleGameSettleReprot(pHandler, inputPkg);
            break;
        }
        case record::RECORD_BACKEND_GAME_END:{
            /*对局结束事件*/
            HandleGameEndReprot(pHandler, inputPkg);
            break;
        }
        case record::RECORD_BACKEND_GAME_JACKPOP:{
            /*奖池赔付事件*/
            HandleGameJackpotReport(pHandler, inputPkg);
            break;
        }
        case record::RECORD_BACKEND_GAME_CANCEL_BET:
        {
            /*取消下注事件*/
            HandleGameCancelBetReport(pHandler, inputPkg);
            break;
        }
        default:{
            log_error("ProcessPacket not handle cmd=%u", cmd);
            break;
        }
    }

	return 0;
}

int CGameServer::ProcGameInit(int ev_id, SpiderEvent* pEvent)
{

	return 0;
}
bool CGameServer::ReadCommonConf(const char* strxml)
{
	CMarkupSTL  markup;
	if (!markup.Load(strxml))
	{
		log_error("Load xml %s failed", strxml);
		return false;
	}

	if (!markup.FindElem("application"))
	{
		log_error("Not Found Elem [application] in xml[%s]", strxml);
		return false;
	}

	if (!markup.IntoElem())
	{
		log_error("IntoElem [application] failed.");
		return false;
	}

	if (!markup.FindElem("phppost"))
	{
		log_error("Not Found Elem [php] in xml[%s]", strxml);
		return false;
	}
	else
	{
	    m_httpListenPort = atoi(markup.GetAttrib("port").c_str());
	    log_debug("ReadCommonConf m_httpListenPort=%d", m_httpListenPort);
	}

    if (!markup.FindElem("path"))
    {
        log_error("FindElem [path] failed.");
        return false;
    }
    else
    {
        m_strPath = markup.GetAttrib("file");
        log_debug("m_strPath=%s\n", m_strPath.c_str());
    }

	log_debug("ReadCommonConf succ!!");

	return true;
}

/*********************************GAME REQUEST**************************/
/*上报 游戏下注事件*/
bool CGameServer::HandleGameBetReprot(SocketHandler *pHandler, NETInputPacket *inputPkg)
{
    Timer t;
	record::GameBetEventReport stReq;
	bool bRet = inputPkg->parsePb(&stReq);
	if (!bRet)
	{
		log_error("parse failed");
		return false;
	}
    int32_t ccgame_id = stReq.game_ctype().ccgame_id();
    if (ccgame_id <= 0)
    {
        log_error("ccgame_id <= 0");
        return false;
    }
    record::GameClassType gct = stReq.game_ctype();

    // Encode成JSON保存
    Json::FastWriter writer;
    Json::Value eventRoot;
    CGameServer::CommGameField(eventRoot, gct);
    eventRoot["event"]      = EVENT_TYPE::BET;
    eventRoot["multi"]      = 0;
    // eventRoot["ext_json"]   = stReq.ext_json();

    /*game_event_(gameid)_(date)*/
    std::string GameEventTable,GameRoundDetailTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, GameEventTable);

    bool bExists = false;
    /*EventVec*/
    std::vector<std::pair<std::string, std::string>> GameBetEventTableVec;

    /*Autokey*/
    std::string EventAutoIncVal = "1", DetailAutoIncVal = "1", EventAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EventAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, EventAutoIncVal, bExists);
    
    /*Autoval*/
    std::string AutoEventId = std::to_string(stReq.lottery_info_size() + std::stoi(EventAutoIncVal));
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, AutoEventId);

    Json::Value parseExtJs = ParseExtJson(stReq.ext_json());
	// 用户首次操作记录数据
    std::vector<std::pair<std::string, std::string>> GameBetFirstVec;
    std::string strKey = "", strValue = "0";
    for (int idx = 0; idx < stReq.lottery_info_size(); ++idx)
    {
        const record::LotteryInfo& LotteryInfo = stReq.lottery_info(idx);
        eventRoot["id"]      = std::stoi(EventAutoIncVal) + idx;
        eventRoot["uid"]     = LotteryInfo.uid();
        eventRoot["amount"]  = static_cast<Json::Int64>(LotteryInfo.bet_amount()); // 押注和结算金额
        eventRoot["bet_amount"]  = static_cast<Json::Int64>(LotteryInfo.bet_amount()); // 押注和结算金额
        eventRoot["cycle"]   = LotteryInfo.cycle();
        eventRoot["app_comp_id"]     = LotteryInfo.app_comp_id(); // 厂商
        eventRoot["app_type"]        = LotteryInfo.app_type();    // 客户端类型
        eventRoot["app_id"]          = LotteryInfo.app_id();      // 厂商appid
        eventRoot["opreate_time"]    = static_cast<Json::Int64>(LotteryInfo.opreate_time()) ? static_cast<Json::Int64>(LotteryInfo.opreate_time()) : static_cast<Json::Int64>(time(NULL)); // 操作时间 // 操作时间
        eventRoot["ext_json"]        = MergeJsonData(parseExtJs, LotteryInfo.ext_json());//扩展字段不做额外的处理源数据
        eventRoot["agency_id"]       = LotteryInfo.agency_id();//代理商
        eventRoot["order_id"]        = static_cast<Json::Int64>(LotteryInfo.order_id());//require,交易序号,统一运营商序号
        eventRoot["is_ai"]           = (bool)LotteryInfo.is_ai();//是否是机器人 false默认不是机器人

        this->ConcatEventFirstKey(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EVENT_TYPE::BET, LotteryInfo.uid(), strKey);
        this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, strValue, bExists);
        eventRoot["is_first"] = !bExists;    // 是否首次
        std::string saveEventValue = writer.write(eventRoot);
        GameBetEventTableVec.push_back(std::make_pair(eventRoot["id"].asString(), saveEventValue));

//        // 索引
//        std::string AssociationBetKey = "bet_" + LotteryInfo.cycle();
//        GameBetEventTableVec.push_back(std::make_pair(AssociationBetKey, eventRoot["id"].asString()));

        //更新首次上报记录
        if (!bExists)
        {
            GameBetFirstVec.push_back(std::make_pair(strKey, "1"));
//            this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, "1");
        }
        // log_info("uid:{%u},BetEvent:{%s},BetEventId:{%d}", LotteryInfo.uid(), saveEventValue.c_str(), eventRoot["id"].asInt());
        Json::Value logEntry;
        logEntry["uid"] = LotteryInfo.uid();
        logEntry["BetEvent_info"] = saveEventValue;
        logEntry["BetEventId"] = eventRoot["id"];
        t.Append(logEntry);
    }
    //写入游戏下注事件表
    if (!GameBetEventTableVec.empty())
        this->m_rocksdbHandler->PutWithBatch(GameEventTable, GameBetEventTableVec);
    if(!GameBetFirstVec.empty()){
        this->m_rocksdbHandler->PutWithBatch(GAME_EVENT_GLOBAL_TABLE, GameBetFirstVec);
    }
    // log_debug("ccgame_id=%d, level_id=%d, dstid=%s, ", gct.ccgame_id(), gct.level_id(), stReq.DebugString().c_str());
    Json::Value logEntry;
    logEntry["ccgame_id"] = gct.ccgame_id();
    logEntry["level_id"] = gct.level_id();
    logEntry["pb_info"] = stReq.DebugString();
    t.Append(logEntry);
    return true;
}

/*上报 玩家结算事件*/
bool CGameServer::HandleGameSettleReprot(SocketHandler *pHandler, NETInputPacket *inputPkg)
{
    Timer t;
    record::GameSettleEventReport stReq;
    bool bRet = inputPkg->parsePb(&stReq);
    log_debug("stReq=%s", stReq.DebugString().c_str());
    if (!bRet)
    {
        log_error("parse failed");
        return false;
    }
    int32_t ccgame_id = stReq.game_ctype().ccgame_id();
    if (ccgame_id <= 0)
    {
        log_error("ccgame_id <= 0");
        return false;
    }
    record::GameClassType gct = stReq.game_ctype();

    // Encode成JSON保存
    Json::FastWriter writer;
    Json::Value eventRoot;
    CGameServer::CommGameField(eventRoot, gct);
    eventRoot["event"]      = EVENT_TYPE::SETTLE;
    eventRoot["multi"]      = 0;
    // eventRoot["ext_json"]   = stReq.ext_json();

    Json::Value settleRoot;
    CGameServer::CommGameField(settleRoot, gct);
    // settleRoot["ext_json"]       = stReq.ext_json();
    // settleRoot["result_string"]  = stReq.result_string();   //开奖结果
    // settleRoot["bet_string"]     = stReq.bet_string();  //投注内容

    /*游戏下注事件表名 game_event_101_20240730/游戏开奖明细表 game_round_detail_101_20240730*/
    std::string GameEventTable,GameRoundDetailTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, GameEventTable);
    this->ConcatTableName(const_cast<std::string&>(GAME_ROUND_DETAIL_TABLE), ccgame_id, GameRoundDetailTable);

    bool bExists = false;
    /*结算事件表vector/开奖明细表vector*/
    std::vector<std::pair<std::string, std::string>> GameBetEventTableVec;
    std::vector<std::pair<std::string, std::string>> GameDetailEventTableVec;

    /*事件表自增/开奖明细表自增*/
    std::string EventAutoIncVal = "1", DetailAutoIncVal = "1";
    std::string EventAutoIncKey = "_id", DetailAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EventAutoIncKey);
    this->ConcatTableName(const_cast<std::string&>(GAME_ROUND_DETAIL_TABLE), ccgame_id, DetailAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, EventAutoIncVal, bExists);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), DetailAutoIncKey, DetailAutoIncVal, bExists);

    /*回写自增表IDKey事件表自增和开奖明细表自增*/
    std::string AutoEventId  = std::to_string(stReq.settle_info_size() + std::stoi(EventAutoIncVal));
    std::string AutoDetailId = std::to_string(stReq.settle_info_size() + std::stoi(DetailAutoIncVal));
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, AutoEventId);
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), DetailAutoIncKey, AutoDetailId);

    Json::Value parseExtJs = ParseExtJson(stReq.ext_json());
    Json::Value parseResultJs = ParseExtJson(stReq.result_string());
    Json::Value parseBetJs = ParseExtJson(stReq.bet_string());
	// 用户首次操作记录数据
    std::vector<std::pair<std::string, std::string>> GameBetFirstVec;
    std::string strKey = "", strValue = "0";
    /*批处理循环处理下注消息*/
    for (int idx = 0; idx < stReq.settle_info_size(); ++idx)
    {
        const record::SettleInfo& Settle = stReq.settle_info(idx);

        /*事件*/
        eventRoot["id"]      = std::stoi(EventAutoIncVal) + idx;
        eventRoot["uid"]     = Settle.uid();
        eventRoot["amount"]  = static_cast<Json::Int64>(Settle.settle_amount()); //结算金额
        eventRoot["multi"]   = static_cast<Json::Int64>(Settle.settle_multi());  //结算倍数
        eventRoot["bet_amount"]   = static_cast<Json::Int64>(Settle.bet_amount());  //玩家押注金额
        eventRoot["cycle"]   = Settle.cycle();
        eventRoot["win_num"] = Settle.win_num(); // 玩家连赢场数
        eventRoot["tax_amount"] = static_cast<Json::Int64>(Settle.tax_amount()); // 玩家税收
        eventRoot["app_comp_id"]     = Settle.app_comp_id(); // 厂商
        eventRoot["app_type"]        = Settle.app_type();    // 客户端类型
        eventRoot["app_id"]          = Settle.app_id();      // 厂商appid
        eventRoot["opreate_time"]    = static_cast<Json::Int64>(Settle.opreate_time()) ? static_cast<Json::Int64>(Settle.opreate_time()) : static_cast<Json::Int64>(time(NULL)); // 操作时间
        eventRoot["ext_json"]        = MergeJsonData(parseExtJs, Settle.ext_json());//扩展字段不做额外的处理源数据
        eventRoot["agency_id"]       = Settle.agency_id();//代理商
        eventRoot["order_id"]        = static_cast<Json::Int64>(Settle.order_id());//require,交易序号,统一运营商序号
        eventRoot["is_ai"]           = Settle.is_ai();
        /*获取玩家是否首次上报记录game_event_(cc_game_id)_(bet)_(uid)*/
        // std::string strKey = "";
        // std::string strValue = "0";
        this->ConcatEventFirstKey(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EVENT_TYPE::SETTLE, Settle.uid(), strKey);
        this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, strValue, bExists);
        eventRoot["is_first"] = !bExists;
        std::string saveEventValue = writer.write(eventRoot);
        GameBetEventTableVec.push_back(std::make_pair(eventRoot["id"].asString(), saveEventValue));
        
        /*明细*/
        settleRoot["id"]                  = std::stoi(DetailAutoIncVal) + idx;
        settleRoot["uid"]                 = Settle.uid();
        settleRoot["bet_amount"]          = static_cast<Json::Int64>(Settle.bet_amount());       // 玩家下注
        settleRoot["settle_amount"]       = static_cast<Json::Int64>(Settle.settle_amount());    // 结算金额
        settleRoot["settle_multi"]        = static_cast<Json::Int64>(Settle.settle_multi());     // 结算倍数
        settleRoot["round_rank"]          = Settle.round_rank();                                 // 排名
        settleRoot["is_ai"]               = Settle.is_ai();                                      // 默认false不是AI
        settleRoot["bet_time"]            = static_cast<Json::Int64>(Settle.start_time());                                 // (开始时间)->对局时间
        settleRoot["settle_time"]         = static_cast<Json::Int64>(Settle.end_time());                                   // (结束时间)->开奖时间
        settleRoot["cycle"]               = Settle.cycle();
        settleRoot["tax_amount"]          = static_cast<Json::Int64>(Settle.tax_amount()); // 玩家税收
        settleRoot["app_comp_id"]         = Settle.app_comp_id(); // 厂商
        settleRoot["app_type"]            = Settle.app_type();    // 客户端类型
        settleRoot["app_id"]              = Settle.app_id();      // 厂商appid
        settleRoot["ext_json"]            = MergeJsonData(parseExtJs, Settle.ext_json());//扩展字段不做额外的处理源数据
        settleRoot["result_string"]       = MergeJsonData(parseResultJs, Settle.result_string());//扩展字段不做额外的处理源数据//开奖结果
        settleRoot["bet_string"]          = MergeJsonData(parseBetJs, Settle.bet_string());//扩展字段不做额外的处理源数据//投注内容
        std::string saveDetailValue = writer.write(settleRoot);
        GameDetailEventTableVec.push_back(std::make_pair(settleRoot["id"].asString(), saveDetailValue));

//        // 索引
//        std::string AssociationDetailkey = "detail_" + Settle.cycle();
//        GameDetailEventTableVec.push_back(std::make_pair(AssociationDetailkey, settleRoot["id"].asString()));

        //更新首次上报记录
        if (!bExists)
        {
            GameBetFirstVec.push_back(std::make_pair(strKey, "1"));
//            this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, "1");
        }
        Json::Value logEntry;
        logEntry["uid"] = Settle.uid();
        logEntry["SettleEventId"] = eventRoot["id"];
        logEntry["SettleEvent_info"] = saveEventValue;
        logEntry["SettleId"] = settleRoot["id"];
        logEntry["Settle_info"] = saveDetailValue;
        t.Append(logEntry);
        // log_info("uid:{%u},SettleEvent:{%s},SettleEventId:{%d}", Settle.uid(), saveEventValue.c_str(), eventRoot["id"].asInt());
        // log_info("uid:{%u},Settle:{%s},SettleId:{%d}", Settle.uid(), saveDetailValue.c_str(), settleRoot["id"].asInt());
    }
    //写入游戏开奖明细表
    if (!GameDetailEventTableVec.empty())
    {
        this->m_rocksdbHandler->PutWithBatch(GameRoundDetailTable, GameDetailEventTableVec);
    }
    //写入游戏下注事件表
    if (!GameBetEventTableVec.empty())
    {
        this->m_rocksdbHandler->PutWithBatch(GameEventTable, GameBetEventTableVec);
    }
    if(!GameBetFirstVec.empty()){
        this->m_rocksdbHandler->PutWithBatch(GAME_EVENT_GLOBAL_TABLE, GameBetFirstVec);
    }
    // log_debug("ccgame_id=%d, level_id=%d, dstid=%s, ", gct.ccgame_id(), gct.level_id(), stReq.DebugString().c_str());
    Json::Value logEntry;
    logEntry["ccgame_id"] = gct.ccgame_id();
    logEntry["level_id"] = gct.level_id();
    logEntry["pb_info"] = stReq.DebugString();
    t.Append(logEntry);
    return true;
}

/*上报 游戏对局结束*/
bool CGameServer::HandleGameEndReprot(SocketHandler *pHandler, NETInputPacket *inputPkg)
{
    Timer t;
    record::GameRecordReport stReq;
    bool bRet = inputPkg->parsePb(&stReq);
    if (!bRet)
    {
        log_error("parse failed");
        return false;
    }
    int32_t ccgame_id = stReq.game_ctype().ccgame_id();
    if (ccgame_id <= 0)
    {
        log_error("ccgame_id <= 0");
        return false;
    }
    // Encode成JSON保存
    Json::FastWriter writer;
    record::GameClassType gct = stReq.game_ctype();
    bool bExists = false;

    /*事件表自增/开奖表自增*/
    std::string EventAutoIncVal = "1" , SettleAutoIncVal = "1";
    std::string EventAutoIncKey = "_id", SettleAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EventAutoIncKey);
    this->ConcatTableName(const_cast<std::string&>(GAME_ROUND_SETTLE_TABLE), ccgame_id, SettleAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, EventAutoIncVal, bExists);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), SettleAutoIncKey, SettleAutoIncVal, bExists);

    /*回写自增表IDKey事件表自增和开奖表自增*/
    std::string AutoEventId  = std::to_string(1 + std::stoi(EventAutoIncVal));
    std::string AutoSettleId = std::to_string(1 + std::stoi(SettleAutoIncVal));
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, AutoEventId);
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), SettleAutoIncKey, AutoSettleId);

    /*开奖表名/事件表名*/
    std::string GameEventTable,GameRoundSettleTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, GameEventTable);
    this->ConcatTableName(const_cast<std::string&>(GAME_ROUND_SETTLE_TABLE), ccgame_id, GameRoundSettleTable);

    /*事件表*/
    Json::Value eventRoot;
    CGameServer::CommGameField(eventRoot, gct);
    eventRoot["id"]         = std::stoi(EventAutoIncVal);
    eventRoot["event"]      = EVENT_TYPE::BOMP;
    eventRoot["amount"]     = 0;//牌局结束事件玩家没有结算金额和下注金额
    eventRoot["multi"]      = static_cast<Json::Int64>(stReq.settle_multi());
    eventRoot["ext_json"]   = stReq.ext_json();
    eventRoot["opreate_time"] = static_cast<Json::Int64>(stReq.opreate_time()) ? static_cast<Json::Int64>(stReq.opreate_time()) : static_cast<Json::Int64>(time(NULL));
    std::string saveEventValue = writer.write(eventRoot);
    this->m_rocksdbHandler->WriteValueToDB(GameEventTable, EventAutoIncVal, saveEventValue);

    /*结算表*/
    Json::Value settleRoot;
    CGameServer::CommGameField(settleRoot, gct);
    settleRoot["id"]            = std::stoi(SettleAutoIncVal);
    settleRoot["start_time"]    = static_cast<Json::Int64>(stReq.start_time());
    settleRoot["end_time"]      = static_cast<Json::Int64>(stReq.end_time());
    settleRoot["user_num"]      = stReq.user_num();
    settleRoot["ai_num"]        = stReq.ai_num();
    settleRoot["ext_json"]      = stReq.ext_json();         // 扩展json
    settleRoot["bet_times_user"]          = stReq.bet_times_user(); // 玩家总下注次数
    settleRoot["bet_amount_user"]         = static_cast<Json::Int64>(stReq.bet_amount_user()); // 玩家总投入
    settleRoot["settle_amount_user"]      = static_cast<Json::Int64>(stReq.settle_amount_user()); // 玩家总产出
    settleRoot["bet_times_ai"]            = stReq.bet_times_ai(); // ai总下注次数
    settleRoot["bet_amount_ai"]           = static_cast<Json::Int64>(stReq.bet_amount_ai()); // ai总投入
    settleRoot["settle_amount_ai"]        = static_cast<Json::Int64>(stReq.settle_amount_ai()); // ai总产出
    settleRoot["settle_amount_max"]       = static_cast<Json::Int64>( stReq.settle_amount_max()); // 玩家最大结算金额
    settleRoot["settle_multi_max"]        = static_cast<Json::Int64>(stReq.settle_multi_max()); // 玩家最大结算倍数
    settleRoot["bomp_multi"]              = static_cast<Json::Int64>(stReq.settle_multi()); // 爆炸倍数
    settleRoot["settle_tax_user"]         = static_cast<Json::Int64>(stReq.settle_tax_user()); // 玩家产出盈利后，平台抽成
    settleRoot["settle_tax_ai"]           = static_cast<Json::Int64>(stReq.settle_tax_ai()); // ai产出盈利后，平台的抽成
    settleRoot["result_string"]           = stReq.result_string();    // 开奖结果
    settleRoot["room_pool"]               = static_cast<Json::Int64>(stReq.room_pool()); // 房间水池
    settleRoot["settle_type"]             = stReq.settle_type(); // 结算类型
    settleRoot["win_user_num"]            = stReq.win_user_num(); // 总胜利玩家数
    settleRoot["validbet_user_num"]       = stReq.validbet_user_num(); // 有效下注人数
    settleRoot["parent_round_no"]         = static_cast<Json::Int64>(stReq.parent_round_no()); // 对局分组号
    std::string saveSettleValue = writer.write(settleRoot);
    this->m_rocksdbHandler->WriteValueToDB(GameRoundSettleTable, SettleAutoIncVal, saveSettleValue);

    /*牌局回放表自增*/
    std::string ReplayAutoIncVal = "1";
    std::string ReplayAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_ROUND_REPLAY_TABLE), ccgame_id, ReplayAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), ReplayAutoIncKey, ReplayAutoIncVal, bExists);
    int replayID = std::stoi(ReplayAutoIncVal);
    std::vector<std::pair<std::string, std::string>> replayTableVec;
    // 牌局回放表
    std::string GameReplayTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_ROUND_REPLAY_TABLE), ccgame_id, GameReplayTable);
    Json::Value replayRoot;
    CGameServer::CommGameField(replayRoot, gct);
    for (int i = 0; i < stReq.replay_array_size(); ++i){
        const record::ReplayInfo& info = stReq.replay_array(i);
        replayRoot["uid"] = (uint32)info.uid();
        replayRoot["bet_amount"] = (Json::Int64)info.bet_amount();
        replayRoot["is_ai"] = (bool)info.is_ai();
        replayRoot["cycle"] = info.cycle();
        if(info.opreate_time() != 0){
            replayRoot["opreate_time"] = (Json::Int64)info.opreate_time();
        }
        replayRoot["ext_json"] = info.ext_json();
        replayRoot["action"] = info.action();
        replayRoot["app_id"] = (int)info.app_id();
        replayRoot["id"] = replayID;
        std::string saveReplayValue = writer.write(replayRoot);
        replayTableVec.push_back(std::make_pair(std::to_string(replayID), saveReplayValue));
        replayID++;
    }
    if (!replayTableVec.empty()){
        this->m_rocksdbHandler->PutWithBatch(GameReplayTable, replayTableVec);
        std::string AutoReplayId = std::to_string(replayID);
        this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), ReplayAutoIncKey, AutoReplayId);
    }

    // log_info("GameEnd:{%s},GameEndEventId:{%d}", saveEventValue.c_str(), eventRoot["id"].asInt());
    // log_info("GameEndSettle:{%s},GameEndSettleId:{%d}", saveSettleValue.c_str(), settleRoot["id"].asInt());
    // log_debug("ccgame_id=%d, level_id=%d, dstid=%s, ", gct.ccgame_id(), gct.level_id(), stReq.DebugString().c_str());
    Json::Value logEntry;
    logEntry["GameEndEventId"] = eventRoot["id"];
    logEntry["GameEnd_info"] = saveEventValue;
    logEntry["GameEndSettleId"] = settleRoot["id"];
    logEntry["GameEndSettle_info"] = saveSettleValue;
    logEntry["ccgame_id"] = gct.ccgame_id();
    logEntry["level_id"] = gct.level_id();
    logEntry["pb_info"] = stReq.DebugString();
    t.Append(logEntry);
    
    return true;
}

/*上报 玩家进入房间事件*/
bool CGameServer::HandleGameEnterRoomeprot(SocketHandler *pHandler, NETInputPacket *inputPkg)
{
    Timer t;
    record::GameEnterRoomEventReport stReq;
    bool bRet = inputPkg->parsePb(&stReq);
    if (!bRet)
    {
        log_error("parse HandleGameEnterRoomeprot failed");
        return false;
    }
    int32_t ccgame_id = stReq.game_ctype().ccgame_id();
    if (ccgame_id <= 0)
    {
        log_error("ccgame_id <= 0");
        return false;
    }
    // Encode成JSON保存
    Json::FastWriter writer;

    /*事件表自增*/
    bool bExists = false;
    std::string EventAutoIncVal = "1", EventAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EventAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, EventAutoIncVal, bExists);

    std::string AutoEventId = std::to_string(1 + std::stoi(EventAutoIncVal));
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, AutoEventId);

    record::GameClassType gct = stReq.game_ctype();

    /*事件表*/
    Json::Value eventRoot;
    EventJson(eventRoot, EVENT_TYPE::ENTER, gct, &stReq);
    eventRoot["id"]         = std::stoi(EventAutoIncVal);
    eventRoot["uid"]        = stReq.uid();
    eventRoot["ext_json"]   = stReq.ext_json();
    eventRoot["app_comp_id"]     = stReq.app_comp_id(); // 厂商
    eventRoot["app_type"]        = stReq.app_type();    // 客户端类型
    eventRoot["app_id"]          = stReq.app_id();      // app名称
    eventRoot["opreate_time"] = static_cast<Json::Int64>(stReq.opreate_time()) ? static_cast<Json::Int64>(stReq.opreate_time()) : static_cast<Json::Int64>(time(NULL));
    eventRoot["agency_id"]          = stReq.agency_id();      // 代理商
    eventRoot["is_ai"]          = (bool)stReq.is_ai();      // 是否是机器人 false默认不是机器人

    //是否首次上报记录
    std::string strKey = "", strValue = "0";
    this->ConcatEventFirstKey(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), ccgame_id, EVENT_TYPE::ENTER, stReq.uid(), strKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, strValue, bExists);
    eventRoot["is_first"] = !bExists;
    std::string saveEventValue = writer.write(eventRoot);

    /*写入事件表*/
    std::string GameEventTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, GameEventTable);
    this->m_rocksdbHandler->WriteValueToDB(GameEventTable, EventAutoIncVal, saveEventValue);

    //更新首次上报记录
    if (!bExists)
    {
        this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, "1");
    }
    // log_info("uid:{%u},EnterRoom:{%s},EnterRoomEventId:{%d}",stReq.uid(), saveEventValue.c_str(), eventRoot["id"].asInt());
    // log_debug("ccgame_id=%d, level_id=%d, dstid=%s, ", gct.ccgame_id(), gct.level_id(), stReq.DebugString().c_str());
    Json::Value logEntry;
    logEntry["uid"] = stReq.uid();
    logEntry["EnterRoomEventId"] = eventRoot["id"];
    logEntry["EnterRoom_info"] = saveEventValue;
    logEntry["ccgame_id"] = gct.ccgame_id();
    logEntry["level_id"] = gct.level_id();
    logEntry["pb_info"] = stReq.DebugString();
    t.Append(logEntry);
    return true;
}

/*上报 奖池事件*/
bool CGameServer::HandleGameJackpotReport(SocketHandler *pHandler, NETInputPacket *inputPkg)
{
    Timer t;
    record::GameJackpotReport stReq;
	bool bRet = inputPkg->parsePb(&stReq);
	if (!bRet)
	{
		log_error("parse failed");
		return false;
	}
    int32_t ccgame_id = stReq.game_ctype().ccgame_id();
    if (ccgame_id <= 0)
    {
        log_error("ccgame_id <= 0");
        return false;
    }
    record::GameClassType gct = stReq.game_ctype();

    // Encode成JSON保存
    Json::FastWriter writer;
    Json::Value eventRoot;
    CGameServer::CommGameField(eventRoot, gct);
    eventRoot["event"]      = EVENT_TYPE::JACKPOT;
    // eventRoot["multi"]      = 0;
    // eventRoot["ext_json"]   = stReq.ext_json();

    /*game_event_(gameid)_(date)*/
    std::string GameEventTable,GameRoundDetailTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, GameEventTable);

    bool bExists = false;
    /*EventVec*/
    std::vector<std::pair<std::string, std::string>> GameBetEventTableVec;

    /*Autokey*/
    std::string EventAutoIncVal = "1", DetailAutoIncVal = "1", EventAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EventAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, EventAutoIncVal, bExists);
    
    /*Autoval*/
    std::string AutoEventId = std::to_string(stReq.jackpot_info_size() + std::stoi(EventAutoIncVal));
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, AutoEventId);

    Json::Value parseExtJs = ParseExtJson(stReq.ext_json());
	// 用户首次操作记录数据
    std::vector<std::pair<std::string, std::string>> GameBetFirstVec;
    std::string strKey = "", strValue = "0";
    for (int idx = 0; idx < stReq.jackpot_info_size(); ++idx)
    {
        const record::JackpotInfo& JackpotInfo = stReq.jackpot_info(idx);
        eventRoot["id"]             = std::stoi(EventAutoIncVal) + idx;
        eventRoot["uid"]            = JackpotInfo.uid();
        eventRoot["bet_amount"]     = static_cast<Json::Int64>(JackpotInfo.bet_amount());     //玩家下注金额
        eventRoot["amount"]  = static_cast<Json::Int64>(JackpotInfo.settle_amount());         //玩家结算金额
        eventRoot["settle_multi"]   = static_cast<Json::Int64>(JackpotInfo.settle_multi());   //玩家结算倍数
        eventRoot["jackpot_amount"] = static_cast<Json::Int64>(JackpotInfo.jackpot_amount()); //玩家获得奖池金额
        eventRoot["jackpot_type"]   = JackpotInfo.jackpot_type();                             //玩家获得奖池挡位
        eventRoot["app_comp_id"]    = JackpotInfo.app_comp_id(); // 厂商
        eventRoot["app_type"]       = JackpotInfo.app_type();    // 客户端类型
        eventRoot["app_id"]         = JackpotInfo.app_id();      // 厂商appid
        eventRoot["win_num"]        = JackpotInfo.win_num();     // 玩家连赢次数
        eventRoot["opreate_time"]   = static_cast<Json::Int64>(JackpotInfo.opreate_time()) ? static_cast<Json::Int64>(JackpotInfo.opreate_time()) : static_cast<Json::Int64>(time(NULL));
        eventRoot["ext_json"]       = MergeJsonData(parseExtJs, JackpotInfo.ext_json());//扩展字段不做额外的处理源数据
        eventRoot["agency_id"]         = JackpotInfo.agency_id();     // 代理商
        eventRoot["order_id"]         = static_cast<Json::Int64>(JackpotInfo.order_id());     // require,交易序号,统一运营商序号

        this->ConcatEventFirstKey(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EVENT_TYPE::JACKPOT, JackpotInfo.uid(), strKey);
        this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, strValue, bExists);
        eventRoot["is_first"] = !bExists;    // 是否首次
        std::string saveEventValue = writer.write(eventRoot);
        GameBetEventTableVec.push_back(std::make_pair(eventRoot["id"].asString(), saveEventValue));

//        // 索引
//        std::string AssociationBetKey = "jackpot_" + JackpotInfo.cycle();
//        GameBetEventTableVec.push_back(std::make_pair(AssociationBetKey, eventRoot["id"].asString()));

        //更新首次上报记录
        if (!bExists)
        {
            GameBetFirstVec.push_back(std::make_pair(strKey, "1"));
//            this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, "1");
        }
        Json::Value logEntry;
        logEntry["uid"] = JackpotInfo.uid();
        logEntry["JackpotEvent_info"] = saveEventValue;
        logEntry["JackpotId"] = eventRoot["id"];
        t.Append(logEntry);
        // log_info("uid:{%u},Jackpot:{%s},JackpotEventId:{%d}",JackpotInfo.uid(), saveEventValue.c_str(), eventRoot["id"].asInt());
    }
    //写入游戏下注事件表
    if (!GameBetEventTableVec.empty())
        this->m_rocksdbHandler->PutWithBatch(GameEventTable, GameBetEventTableVec);
    if(!GameBetFirstVec.empty()){
        this->m_rocksdbHandler->PutWithBatch(GAME_EVENT_GLOBAL_TABLE, GameBetFirstVec);
    }
    // log_debug("ccgame_id=%d, level_id=%d, dstid=%s, ", gct.ccgame_id(), gct.level_id(), stReq.DebugString().c_str());
    Json::Value logEntry;
    logEntry["ccgame_id"] = gct.ccgame_id();
    logEntry["level_id"] = gct.level_id();
    logEntry["pb_info"] = stReq.DebugString();
    t.Append(logEntry);
    return true;
}

/*上报 取消下注事件*/
bool CGameServer::HandleGameCancelBetReport(SocketHandler *pHandler, NETInputPacket *inputPkg)
{
    Timer t;
    record::GameCancelBetReport stReq;
	bool bRet = inputPkg->parsePb(&stReq);
	if (!bRet)
	{
		log_error("parse failed");
		return false;
	}
    int32_t ccgame_id = stReq.game_ctype().ccgame_id();
    if (ccgame_id <= 0)
    {
        log_error("ccgame_id <= 0");
        return false;
    }
    record::GameClassType gct = stReq.game_ctype();

    // Encode成JSON保存
    Json::FastWriter writer;
    Json::Value eventRoot;
    CGameServer::CommGameField(eventRoot, gct);
    eventRoot["event"]      = EVENT_TYPE::CANCLE;
    // eventRoot["multi"]      = 0;
    // eventRoot["ext_json"]   = stReq.ext_json();

    /*game_event_(gameid)_(date)*/
    std::string GameEventTable,GameRoundDetailTable = "";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, GameEventTable);

    bool bExists = false;
    /*EventVec*/
    std::vector<std::pair<std::string, std::string>> GameBetEventTableVec;

    /*Autokey*/
    std::string EventAutoIncVal = "1", DetailAutoIncVal = "1", EventAutoIncKey = "_id";
    this->ConcatTableName(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EventAutoIncKey);
    this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, EventAutoIncVal, bExists);
    
    /*Autoval*/
    std::string AutoEventId = std::to_string(stReq.cancel_bet_info_size() + std::stoi(EventAutoIncVal));
    this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), EventAutoIncKey, AutoEventId);

    Json::Value parseExtJs = ParseExtJson(stReq.ext_json());
	// 用户首次操作记录数据
    std::vector<std::pair<std::string, std::string>> GameBetFirstVec;
    std::string strKey = "", strValue = "0";
    for (int idx = 0; idx < stReq.cancel_bet_info_size(); ++idx)
    {
        const record::CancelBetInfo& CancelBetInfo = stReq.cancel_bet_info(idx);
        eventRoot["id"]             = std::stoi(EventAutoIncVal) + idx;
        eventRoot["uid"]            = CancelBetInfo.uid();
        eventRoot["bet_amount"]     = static_cast<Json::Int64>(CancelBetInfo.bet_amount());     //玩家下注金额
        eventRoot["amount"]         = static_cast<Json::Int64>(CancelBetInfo.bet_amount());     //玩家下注金额
        eventRoot["app_comp_id"]    = CancelBetInfo.app_comp_id(); // 厂商
        eventRoot["app_type"]       = CancelBetInfo.app_type();    // 客户端类型
        eventRoot["app_id"]         = CancelBetInfo.app_id();      // 厂商appid
        eventRoot["opreate_time"]   = static_cast<Json::Int64>(CancelBetInfo.opreate_time()) ? static_cast<Json::Int64>(CancelBetInfo.opreate_time()) : static_cast<Json::Int64>(time(NULL));
        eventRoot["ext_json"]       = MergeJsonData(parseExtJs, CancelBetInfo.ext_json());//扩展字段不做额外的处理源数据
        eventRoot["agency_id"]         = CancelBetInfo.agency_id();      // 代理商
        eventRoot["order_id"]       = static_cast<Json::Int64>(CancelBetInfo.order_id());      // require,交易序号,统一运营商序号

        this->ConcatEventFirstKey(const_cast<std::string&>(GAME_EVENT_TABLE), ccgame_id, EVENT_TYPE::CANCLE, CancelBetInfo.uid(), strKey);
        this->m_rocksdbHandler->ReadValueFromDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, strValue, bExists);
        eventRoot["is_first"] = !bExists;    // 是否首次
        std::string saveEventValue = writer.write(eventRoot);
        GameBetEventTableVec.push_back(std::make_pair(eventRoot["id"].asString(), saveEventValue));

//        // 索引
//        std::string AssociationBetKey = "cancle_" + CancelBetInfo.cycle();
//        GameBetEventTableVec.push_back(std::make_pair(AssociationBetKey, eventRoot["id"].asString()));
        // log_debug("AssociationBetKey: %s", AssociationBetKey.c_str());

        //更新首次上报记录
        if (!bExists)
        {
            GameBetFirstVec.push_back(std::make_pair(strKey, "1"));
//            this->m_rocksdbHandler->WriteValueToDB(const_cast<std::string&>(GAME_EVENT_GLOBAL_TABLE), strKey, "1");
        }
        Json::Value logEntry;
        logEntry["uid"] = CancelBetInfo.uid();
        logEntry["CancelBet_info"] = saveEventValue;
        logEntry["CancelBetEventId"] = eventRoot["id"];
        t.Append(logEntry);
        // log_info("uid:{%u},CancelBet:{%s},CancelBetEventId:{%d}",CancelBetInfo.uid(), saveEventValue.c_str(), eventRoot["id"].asInt());
    }
    //写入游戏下注事件表
    if (!GameBetEventTableVec.empty())
        this->m_rocksdbHandler->PutWithBatch(GameEventTable, GameBetEventTableVec);
    if(!GameBetFirstVec.empty()){
        this->m_rocksdbHandler->PutWithBatch(GAME_EVENT_GLOBAL_TABLE, GameBetFirstVec);
    }
    Json::Value logEntry;
    logEntry["ccgame_id"] = gct.ccgame_id();
    logEntry["pb_info"] = stReq.DebugString();
    t.Append(logEntry);
    // log_debug("ccgame_id=%d, dstid=%s, ", gct.ccgame_id(), stReq.DebugString().c_str());
    return true;
}

//php获得表的一些数据
int CGameServer::GetPHPTableData(std::string table_name, int start_id, int64 id, int number, std::vector<std::string>& vecValue)
{
    if (start_id >= id)
    {
        log_error("OnGetMessage  table_name=%s istart_id=%d id=%lld number=%d",
             table_name.c_str(), start_id, id, number);
        return 105;
    }

    std::vector<std::string> vecKey;
    log_debug("OnGetMessage input table_name=%s istart_id=%d id=%lld number=%d",
        table_name.c_str(), start_id, id, number);
    int len = id < (start_id + number) ? id : (start_id + number);
    if (start_id < 0)
    {
        len = id;
        start_id = (id - number) < 0 ? 0 : (id - number);
    }

    log_debug("OnGetMessage final table_name=%s istart_id=%d id=%lld len=%d number=%d",
        table_name.c_str(), start_id, id, len, number);

    for (int i = start_id + 1; i <= len; i++)
    {
        vecKey.push_back(std::to_string(i));
    }

    if (m_rocksdbHandler->MultiGet(table_name, vecKey, vecValue))
    {
        if (vecValue.size() <= 0)
        {
//            log_error("OnGetMessage table_name=%s", table_name.c_str());
//            return 106;
            return 0;
        }
    }
    else
    {
        log_error("OnGetMessage table_name=%s", table_name.c_str());
        return 107;
    }

    return 0;
}

/*拼接表名*/
bool CGameServer::ConcatTableName(std::string strName, int32_t ccgame_id, std::string& table_name)
{
    std::string strTemp = strName + "_" + std::to_string(ccgame_id) + "_" + CTools::GetDateKey(time(NULL));
    if (table_name.empty())
    {
        table_name = strTemp;
    }
    else
    {
        table_name.insert(0, strTemp);
    }
    return true;
}

/*拼接事件是否首次上报Key*/
bool CGameServer::ConcatEventFirstKey(std::string strName, int32_t ccgame_id, EVENT_TYPE type, uint32_t uid, std::string& table_name)
{
    table_name.clear();
    std::string strTemp = strName + "_" + std::to_string(ccgame_id) + "_" + std::to_string(type) + "_" + std::to_string(uid);
    if (table_name.empty())
    {
        table_name = strTemp;
    }
    else
    {
        table_name.insert(0, strTemp);
    }
    return true;
}

std::string CGameServer::ConcatTableNameByDate(const std::string& strName, int32_t ccgame_id, const std::string& strDate){
    std::string strTableName = strName + "_" + std::to_string(ccgame_id) + "_" + strDate;
    return strTableName;
}

void CGameServer::EventJson(Json::Value& root, EVENT_TYPE type, record::GameClassType gct, ::google::protobuf::Message* stReq)
{
    // root["app_comp_id"]     = gct.app_comp_id(); // 厂商
    // root["app_type"]        = gct.app_type();    // 客户端类型
    // root["app_id"]          = gct.app_id();      // app名称
    root["ccgame_id"]       = gct.ccgame_id();   // 游戏名称
    root["uid"]             = 0;                 // 用户id
    root["level_id"]        = gct.level_id();    // 场次id
    root["room_no"]         = gct.room_no();     // 房间号
    root["round_no"]        = gct.round_no();    // 对局号
    root["event"]           = type;              // EVENT_TYPE::BET;
    root["is_first"]        = false;              // 是否首次上报
    root["opreate_time"]    = static_cast<Json::Int64>(time(NULL));        // 操作时间
    root["amount"]          = 0;                 // 结算金额
    root["multi"]           = 0;                 // 结算倍数

    if (record::GameBetEventReport* Request = dynamic_cast<record::GameBetEventReport*>(stReq)) {
        root["ext_json"]        = Request->ext_json();    // 扩展json
    } else if (auto* Request = dynamic_cast<record::GameSettleEventReport*>(stReq)) {
        root["ext_json"]        = Request->ext_json();    // 扩展json
    } else if (auto* Request = dynamic_cast<record::GameEnterRoomEventReport*>(stReq)) {
        root["ext_json"]        = Request->ext_json();    // 扩展json
    }
    // auto set_ext_json = [&root](auto* Request) {
    //     root["ext_json"]        = Request->ext_json();    // 扩展json
    // };
    // set_ext_json(root, dynamic_cast<record::GameBetEventReport*>(stReq));       //下注事件
    // set_ext_json(root, dynamic_cast<record::GameSettleEventReport*>(stReq));    //结算事件
    // set_ext_json(root, dynamic_cast<record::GameEnterRoomEventReport*>(stReq)); //进入房间事件
}

void CGameServer::CommGameField(Json::Value& field, record::GameClassType gct)
{
    // field["app_comp_id"]     = gct.app_comp_id(); // 厂商
    // field["app_type"]        = gct.app_type();    // 客户端类型
    // field["app_id"]          = gct.app_id();      // app名称
    field["ccgame_id"]       = gct.ccgame_id();   // 游戏名称
    field["level_id"]        = gct.level_id();    // 场次id
    field["room_no"]         = gct.room_no();     // 房间号
    field["round_no"]        = gct.round_no();    // 对局号
    field["opreate_time"]    = static_cast<Json::Int64>(time(NULL));    // 操作时间
    field["sub_id"]          = gct.sub_id();      // 子游戏房间号
}


std::string CGameServer::MergeJsonData(Json::Value& SourceRoot, const std::string& DestJson)
{
    if (SourceRoot.isNull() && DestJson.empty())
    {
        return {};
    }

    if (SourceRoot.isNull())
    {
        return DestJson;
    }
    else if(DestJson.empty())
    {
        return SourceRoot.toStyledString();
    }

    Json::Reader Reader;

	// Json::Value SourceRoot;
    // if (!Reader.parse(SourceJson, SourceRoot))
    // {
    //     log_error("SourceJson=%s", SourceJson.c_str());
    //     return std::string();
    // }

    Json::Value DestRoot;
    if (!Reader.parse(DestJson, DestRoot))
    {
        log_error("DestJson=%s", DestJson.c_str());
        return {};
    }

    for (const auto& key : SourceRoot.getMemberNames())
    {
        const auto& value = SourceRoot[key];
        // log_debug("json:key=%s, value=%s", key.c_str(), value.toStyledString().c_str());
        DestRoot[key] = value;
    }
    // log_debug("SourceJson=%s", SourceRoot.toStyledString().c_str());

    // std::for_each(DestRoot.getMemberNames().begin(), DestRoot.getMemberNames().end(),
    //     [&SourceRoot, &DestRoot](const std::string& key)
    //     {
    //         log_debug("json:key=%s, value=%s", key.c_str(), DestRoot[key].toStyledString().c_str());
    //         SourceRoot[key] = DestRoot[key];
    //     }
    // );
    return DestRoot.toStyledString();
}

Json::Value CGameServer::ParseExtJson(const std::string &SourceJson)
{
    Json::Reader Reader;
    Json::Value SourceRoot;
    if (!Reader.parse(SourceJson, SourceRoot))
    {
        return Json::Value();
    }
    return SourceRoot;
}
